#include "OceanWaveFX.h"

OceanWaveFX::OceanWaveFX(ID3D11Device* device)
	:AbstractFX(device, L"FX/OceanWave.fxo")
{
	//Create Input Layout
	InitInputLayout(device);
	//Init shader variables
	InitShaderVariablePointers();
}

OceanWaveFX::~OceanWaveFX()
{}
	
void OceanWaveFX::InitInputLayout(ID3D11Device* device)
{
	//Fillout input layout description.
	const D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[] = 
	{
		{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,	 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0},
		{"TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0}
	};

	//Create our input layout 	
	CreateInputLayout(device, inputLayoutDesc, 4);
}

void OceanWaveFX::InitShaderVariablePointers()
{
	dLightVar = effect->GetVariableByName("dirLightArray");
	dLightCountVar = effect->GetVariableByName("dLightCount")->AsScalar();
	eyePosWVar = effect->GetVariableByName("eyePositionW")->AsVector();

	worldVar = effect->GetVariableByName("world")->AsMatrix();
	viewProjVar = effect->GetVariableByName("viewProj")->AsMatrix();
	worldInvTransVar = effect->GetVariableByName("worldInvTranspose")->AsMatrix();
	worldViewProjVar = effect->GetVariableByName("worldViewProj")->AsMatrix();

	normalTransform0Var = effect->GetVariableByName("normalTransform0")->AsMatrix();
	normalTransform1Var = effect->GetVariableByName("normalTransform1")->AsMatrix();
	displacementTransform0Var = effect->GetVariableByName("displacementTransform0")->AsMatrix();
	displacementTransform1Var = effect->GetVariableByName("displacementTransform1")->AsMatrix();
	textureTransformVar = effect->GetVariableByName("textureTransform")->AsMatrix();

	materialVar = effect->GetVariableByName("mat");

	normalMapVar = effect->GetVariableByName("normalMap")->AsShaderResource();
	normalMapTwoVar = effect->GetVariableByName("normalMapTwo")->AsShaderResource();
	textureMapVar = effect->GetVariableByName("textureMap")->AsShaderResource();
	cubeMapVar = effect->GetVariableByName("cubeMap")->AsShaderResource();

	heightScale0Var	   = effect->GetVariableByName("heightScale0")->AsScalar();
	heightScale1Var    = effect->GetVariableByName("heightScale1")->AsScalar();
	maxTessDistanceVar = effect->GetVariableByName("maxTessDistance")->AsScalar();
	minTessDistanceVar = effect->GetVariableByName("minTessDistance")->AsScalar();
	maxTessFactorVar   = effect->GetVariableByName("maxTessFactor")->AsScalar();
	minTessFactorVar   = effect->GetVariableByName("minTessFactor")->AsScalar();

	//Tile forward data
	llbVar   = effect->GetVariableByName("LightListBuffer")->AsShaderResource();
	llibVar  = effect->GetVariableByName("LightListIndexBuffer")->AsShaderResource();
	llsebVar = effect->GetVariableByName("LightListStartEndBuffer")->AsShaderResource();

	//Render target dimensions.
	rtWidthVar  = effect->GetVariableByName("rtWidth")->AsScalar();
	rtHeightVar = effect->GetVariableByName("rtHeight")->AsScalar();
	
	//Hemispherical lighting
	hemiColDownVar = effect->GetVariableByName("HemiColDown")->AsVector();
	hemiColRangeVar = effect->GetVariableByName("HemiColRange")->AsVector();

	//SSAO
	worldViewVar = effect->GetVariableByName("WorldView")->AsMatrix();
	viewVar = effect->GetVariableByName("View")->AsMatrix();
	ssaoMapVar = effect->GetVariableByName("SSAOMap")->AsShaderResource();
	ssaoWorldViewProjTexVar = effect->GetVariableByName("SSAOWorldViewProjTex")->AsMatrix();
	
	//Shadow map
	shadowMapVar = effect->GetVariableByName("ShadowMap")->AsShaderResource();
	shadowMapViewVar = effect->GetVariableByName("ShadowMapView")->AsMatrix();
	shadowMapProjVar = effect->GetVariableByName("ShadowMapProj")->AsMatrix();
	shadowMapToTexVar = effect->GetVariableByName("ShadowMapToTex")->AsMatrix();
}

void OceanWaveFX::SetShaderResources(ID3D11ShaderResourceView* normalMap, 
	ID3D11ShaderResourceView* normalMapTwo, 
	ID3D11ShaderResourceView* cubeMap, 
	ID3D11ShaderResourceView* tex)
{
	normalMapVar->SetResource(normalMap);
	normalMapTwoVar->SetResource(normalMapTwo);
	textureMapVar->SetResource(tex);
	cubeMapVar->SetResource(cubeMap);
}

void OceanWaveFX::SetPerFrameCbuffer(XMFLOAT3& eye, 
	DirectionalLight* dLights, unsigned dLightCount,
	ID3D11ShaderResourceView* lightListIndexBuffer, 
	ID3D11ShaderResourceView* lightListStartEndBuffer)
{
	//Cap D light count 
	if (dLightCount > MAX_DIRECTIONAL_LIGHT_COUNT)
		dLightCount = MAX_DIRECTIONAL_LIGHT_COUNT;
	eyePosWVar->SetRawValue(&eye, 0, sizeof(XMFLOAT3));
	dLightVar->SetRawValue(dLights, 0, sizeof(DirectionalLight) * dLightCount);
	dLightCountVar->SetInt(dLightCount);

	//Set llib and llseb
	llibVar->SetResource(lightListIndexBuffer);
	llsebVar->SetResource(lightListStartEndBuffer);
}

void OceanWaveFX::SetPerObjectCbuffer(CXMMATRIX& world, CXMMATRIX& viewProj,
		CXMMATRIX& worldInvTrans, CXMMATRIX& worldViewProj,
		CXMMATRIX& normalTrans0, CXMMATRIX& normalTrans1,
		CXMMATRIX& displacementTrans0, CXMMATRIX& displacementTrans1,
		CXMMATRIX& texTrans, Material mat, 
		CXMMATRIX& worldView, CXMMATRIX &view)
{
	worldVar->SetMatrix(reinterpret_cast<const float*>(&world));
	viewProjVar->SetMatrix(reinterpret_cast<const float*>(&viewProj));
	worldInvTransVar->SetMatrix(reinterpret_cast<const float*>(&worldInvTrans));
	worldViewProjVar->SetMatrix(reinterpret_cast<const float*>(&worldViewProj));

	normalTransform0Var->SetMatrix(reinterpret_cast<const float*>(&normalTrans0));
	normalTransform1Var->SetMatrix(reinterpret_cast<const float*>(&normalTrans1));
	displacementTransform0Var->SetMatrix(reinterpret_cast<const float*>(&displacementTrans0));
	displacementTransform1Var->SetMatrix(reinterpret_cast<const float*>(&displacementTrans1));
	textureTransformVar->SetMatrix(reinterpret_cast<const float*>(&texTrans));

	materialVar->SetRawValue(&mat, 0, sizeof(Material));

	worldViewVar->SetMatrix(reinterpret_cast<const float*>(&worldView));
	viewVar->SetMatrix(reinterpret_cast<const float*>(&view));
}

void OceanWaveFX::SetCbufferTessData(float heightScale0, float heightScale1, 
	float maxTessDist, float minTessDist,
	float maxTessFact, float minTessFact)
{
	heightScale0Var->SetFloat(heightScale0);
	heightScale1Var->SetFloat(heightScale1);
	maxTessDistanceVar->SetFloat(maxTessDist);
	minTessDistanceVar->SetFloat(minTessDist);
	maxTessFactorVar->SetFloat(maxTessFact);
	minTessFactorVar->SetFloat(minTessFact);
}

void OceanWaveFX::SetRTDimensions(unsigned width, unsigned height)
{
	rtWidthVar->SetInt(width);
	rtHeightVar->SetInt(height);
}

void OceanWaveFX::SetLightListBuffer(ID3D11ShaderResourceView* lightListBuffer)
{
	llbVar->SetResource(lightListBuffer);
}

void OceanWaveFX::SetHemisphericalData(XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange)
{
	hemiColDownVar->SetRawValue(&hemiColDown, 0, sizeof(XMFLOAT3));
	hemiColRangeVar->SetRawValue(&hemiColRange, 0, sizeof(XMFLOAT3));
}

void OceanWaveFX::SetSSAOData(ID3D11ShaderResourceView* ssaoTex, CXMMATRIX &transform)
{
	ssaoMapVar->SetResource(ssaoTex);
	ssaoWorldViewProjTexVar->SetMatrix(reinterpret_cast<const float*>(&transform));
}

void OceanWaveFX::SetShadowMap(ID3D11ShaderResourceView* shadowMap)
{
	shadowMapVar->SetResource(shadowMap);
}

void OceanWaveFX::SetShadowMapMatricies(CXMMATRIX &view, CXMMATRIX &proj, CXMMATRIX &toTex)
{
	shadowMapViewVar->SetMatrix(reinterpret_cast<const float*>(&view));
	shadowMapProjVar->SetMatrix(reinterpret_cast<const float*>(&proj));
	shadowMapToTexVar->SetMatrix(reinterpret_cast<const float*>(&toTex));
}